#ifndef INSPECTOR_V8INSPECTORCHANNELIMPL_H
#define INSPECTOR_V8INSPECTORCHANNELIMPL_H

#include <locale>
#include <codecvt>
#include "v8-inspector.h"
#include "v8.h"

typedef void (*WriteMessageFunc)(int32_t, const char *);

typedef void (*RunIfWaitingForDebuggerFunc)(int32_t);

class V8InspectorChannelImpl : public v8_inspector::V8Inspector::Channel {
public:
    V8InspectorChannelImpl(const std::unique_ptr<v8_inspector::V8Inspector> &InV8Inspector, const int32_t InCxtGroupID,
                           int32_t InInspectorId) {
        InspectorId = InInspectorId;
        v8_inspector::StringView DummyState;
        V8InspectorSession = InV8Inspector->connect(InCxtGroupID, this, DummyState,
                                                    v8_inspector::V8Inspector::kFullyTrusted);
    }


    virtual ~V8InspectorChannelImpl() override {
        WriteMessageFunc = nullptr;
        V8InspectorSession.reset();
    }

    void DispatchProtocolMessage(const std::string &Message) {
        const auto MessagePtr = reinterpret_cast<const uint8_t *>(Message.c_str());
        const auto MessageLen = (size_t) Message.length();

        v8_inspector::StringView StringView(MessagePtr, MessageLen);
        V8InspectorSession->dispatchProtocolMessage(StringView);
    }

private:
    void SendMessage(v8_inspector::StringBuffer &MessageBuffer) {
        v8_inspector::StringView MessageView = MessageBuffer.string();

        std::string Message;
        if (MessageView.is8Bit()) {
            Message = reinterpret_cast<const char *>(MessageView.characters8());
        } else {
#if _MSC_VER
            std::wstring_convert<std::codecvt_utf8_utf16<uint16_t>, uint16_t> Conv;
            const uint16_t* Start = MessageView.characters16();
#else
            std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> Conv;
            const char16_t *Start = reinterpret_cast<const char16_t *>(MessageView.characters16());
#endif
            Message = Conv.to_bytes(Start, Start + MessageView.length());
        }

        if (WriteMessageFunc)
            WriteMessageFunc(InspectorId, Message.c_str());
    }

    void sendResponse(int CallID, std::unique_ptr<v8_inspector::StringBuffer> Message) override {
        SendMessage(*Message);
    }

    void sendNotification(std::unique_ptr<v8_inspector::StringBuffer> Message) override {
        SendMessage(*Message);
    }

    void flushProtocolNotifications() override {

    }

    std::unique_ptr<v8_inspector::V8InspectorSession> V8InspectorSession;

public:
    WriteMessageFunc WriteMessageFunc;

    int32_t InspectorId;
};

#endif //INSPECTOR_V8INSPECTORCHANNELIMPL_H
